<template>
  <div class="pose-demo">
    <video ref="videoRef" autoplay playsinline muted class="video"></video>
    <canvas ref="canvasRef" class="canvas"></canvas>

    <!-- 掉落的西瓜 -->
    <div
      v-if="fruit && !fruit.exploded"
      class="fruit"
      :style="{
        left: fruit.x + 'px',
        top: fruit.y + 'px',
        backgroundImage: `url(${fruit.image})`
      }"
    ></div>

    <!-- 爆裂动画 -->
    <div
      v-if="fruit && fruit.exploded"
      class="fruit explosion"
      :style="{
        left: fruit.x + 'px',
        top: fruit.y + 'px',
        backgroundImage: `url(${explosionImage})`
      }"
    ></div>

    <!-- 飘起的 +1 分数 -->
    <div
      v-for="(item, index) in floatingScores"
      :key="index"
      class="floating-score"
      :style="{ left: item.x + 'px', top: item.y + 'px' }"
    >
      +{{ item.value }}
    </div>

    <!-- 总分 -->
    <div class="score">分数: {{ score }}</div>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import * as tf from '@tensorflow/tfjs'
import * as posedetection from '@tensorflow-models/pose-detection'
import '@tensorflow/tfjs-backend-webgl'

interface Fruit {
  x: number
  y: number
  speed: number
  value: number
  image: string
  exploded?: boolean
}

interface FloatingScore {
  x: number
  y: number
  value: number
}

const videoRef = ref<HTMLVideoElement | null>(null)
const canvasRef = ref<HTMLCanvasElement | null>(null)

const fruit = ref<Fruit | null>(null)
const score = ref(0)
const floatingScores = ref<FloatingScore[]>([])

const fruitImage = '/images/fruit/xigua.png'
const explosionImage = '/images/fruit/xigua_boom.png'
// 撞中头部的音效
const successSounds = [
  '/audio/audio1.mp3',
  '/audio/audio.mp3',
  '/audio/good.mp3',
  '/audio/unbelivable.mp3'
]

// 西瓜落地失败音效
const failSounds = [
  '/audio/fail.mp3'
]


let detector: posedetection.PoseDetector | null = null
let animationId: number

// 摄像头初始化，输出分辨率和屏幕一致
async function setupCamera() {
  const video = videoRef.value!
  const stream = await navigator.mediaDevices.getUserMedia({
    video: { width: window.innerWidth, height: window.innerHeight },
    audio: false
  })
  video.srcObject = stream
  await new Promise((resolve) => (video.onloadedmetadata = resolve))
  video.play()
}

// 加载模型
async function loadModel() {
  await tf.setBackend('webgl')
  await tf.ready()
  detector = await posedetection.createDetector(
    posedetection.SupportedModels.MoveNet,
    { modelType: posedetection.movenet.modelType.SINGLEPOSE_LIGHTNING }
  )
}

// 创建一个西瓜
function spawnFruit() {
  const fruitWidth = 120
  const screenWidth = window.innerWidth
  fruit.value = {
    x: Math.random() * (screenWidth - fruitWidth),
    y: 0,
    speed: 4 + Math.random() * 3,
    value: 1,
    image: fruitImage,
    exploded: false
  }
}

// 检查头部碰撞
function checkCollision(headX: number, headY: number) {
  if (!fruit.value || fruit.value.exploded) return false
  const fx = fruit.value.x + 60
  const fy = fruit.value.y + 60
  const distance = Math.sqrt((headX - fx) ** 2 + (headY - fy) ** 2)
  return distance < 80
}

// 添加飘起分数
function addFloatingScore(x: number, y: number, value: number) {
  const item: FloatingScore = { x, y, value }
  floatingScores.value.push(item)
  setTimeout(() => {
    floatingScores.value = floatingScores.value.filter((s) => s !== item)
  }, 1000)
}

// 绘制骨架
function drawPose(poses: posedetection.Pose[]) {
  const canvas = canvasRef.value!
  const ctx = canvas.getContext('2d')!
  const video = videoRef.value!

  ctx.clearRect(0, 0, canvas.width, canvas.height)
  ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

  if (poses.length > 0) {
    const nose = poses[0].keypoints[0]
    if (nose && (nose.score ?? 0) > 0.4) {
      // 坐标按比例映射到屏幕
      const scaleX = canvas.width / video.videoWidth
      const scaleY = canvas.height / video.videoHeight
      const headX = nose.x * scaleX
      const headY = nose.y * scaleY

      ctx.beginPath()
      ctx.arc(headX, headY, 8, 0, 2 * Math.PI)
      ctx.fillStyle = 'red'
      ctx.fill()

      if (checkCollision(headX, headY)) {
        handleFruitCollision(headX, headY)
      }
    }
  }
}

function playSound(sounds: string[]) {
  const index = Math.floor(Math.random() * sounds.length)
  const audio = new Audio(sounds[index])
  audio.play()
}

// 碰撞处理
function handleFruitCollision(headX: number, headY: number) {
  if (!fruit.value) return
  fruit.value.exploded = true
  score.value += fruit.value.value
  addFloatingScore(headX, headY, fruit.value.value)
  

  // 播放成功碰撞音效
  playSound(successSounds)

  setTimeout(() => {
    fruit.value = null
    setTimeout(spawnFruit, 500 + Math.random() * 1500)
  }, 500)
}

// 更新西瓜位置
function updateFruit() {
  if (fruit.value && !fruit.value.exploded) {
    fruit.value.y += fruit.value.speed
    const canvas = canvasRef.value!
    if (fruit.value.y > canvas.height) {
      // 播放失败音效
    playSound(failSounds)
      fruit.value = null
      setTimeout(spawnFruit, 500 + Math.random() * 1500)
    }
  }
}

// 主循环
async function detectPose() {
  if (detector && videoRef.value) {
    const poses = await detector.estimatePoses(videoRef.value)
    drawPose(poses)
    updateFruit()
  }
  animationId = requestAnimationFrame(detectPose)
}

onMounted(async () => {
  await setupCamera()
  await loadModel()

  // 设置 canvas 尺寸为屏幕尺寸
  const canvas = canvasRef.value!
  canvas.width = window.innerWidth
  canvas.height = window.innerHeight

  spawnFruit()
  detectPose()
})
</script>

<style lang="scss" scoped>
.pose-demo {
  position: relative;
  width: 100vw;
  height: 100vh;
  overflow: hidden;
}
.video,
.canvas {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}
.fruit {
  position: absolute;
  width: 120px;
  height: 120px;
  background-size: cover;
  pointer-events: none;
}
.explosion {
  width: 140px;
  height: 140px;
  animation: boom 0.5s ease-out forwards;
}
@keyframes boom {
  0% { transform: scale(0.5); opacity: 1; }
  100% { transform: scale(1.5); opacity: 0; }
}
.floating-score {
  position: absolute;
  font-size: 24px;
  font-weight: bold;
  color: #ffeb3b;
  text-shadow: 1px 1px 3px black;
  animation: floatUp 1s ease-out forwards;
}
@keyframes floatUp {
  0% { transform: translateY(0); opacity: 1; }
  100% { transform: translateY(-50px); opacity: 0; }
}
.score {
  position: absolute;
  top: 20px;
  left: 20px;
  font-size: 24px;
  color: yellow;
  font-weight: bold;
  text-shadow: 1px 1px 3px black;
}
</style>
